package site.duanzy.mysql.datasource;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @ClassName: DataSourceAspect
 * @Description: 定义数据源的AOP切面，通过该Service的方法名判断是应该走读库还是写库
 * @author dzy
 * @date 2017年7月28日下午4:41:59
 * @version v1.0
 */
@Aspect			//把这个类声明为一个切面： 1,使用注解“@Aspect”把该类声明为一个切面
@Component		// 2,使用注解“@Component”把该类放入到IOC容器中
public class DataSourceAspect {
	
	/*
	 *正常我们使用 Spring AOP 横切  service 层很容易实现 ，
	 *而在横切 controller 层时却不起作用 。因为  service 层 是由 Spring 负责 扫描管理的 ，
	 *而 controller 层是由 Spring mvc 负责扫描管理的 ，
	 *如果要保证在横切 controller 层 时 也能够实现 aop 功能 ，就必须保证  Spring AOP 的 注解由 Spring mvc 负责扫描 ，
	 *即 开启 Spring aop 的配置要配置在 Spring mvc 的配置文件中 。
	 */
	/**
	 * Pointcut 定义Pointcut，Pointcut名称为aspectjMethod,必须无参，无返回值 只是一个标识，并不进行调用
	 */
	@Pointcut("execution(* site.duanzy.service.*.*(..))")
	private void dataSourcePointcut() {}
	
	/**
	 * 在进入Service方法之前执行
	 * 
	 * @param point
	 *            切面对象
	 */
	@Before("dataSourcePointcut()")
	public void before(JoinPoint point) {
		System.out.println("-------------->执行了");
		// 获取到当前执行的方法名
		String methodName = point.getSignature().getName();
		if (isSlave(methodName)) {
			// 标记为读库
			DynamicDataSourceHolder.markSlave();
		} else {
			// 标记为写库
			DynamicDataSourceHolder.markMaster();
		}
	}

	/**
	 * 判断是否为读库
	 * 
	 * @param methodName
	 * @return
	 */
	private Boolean isSlave(String methodName) {
		// 方法名以query、find、get、select开头的方法名走从库
		return StringUtils.startsWithAny(methodName, "query", "find", "get","select");
	}
}
